﻿using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;

namespace CacheAttribute.Filter
{
    /// <summary>
    /// 缓存名称过滤器
    /// 主要从来对注解中设置的缓存名Total_Name做解析，使之能够像@CacheAble一样解析方法参数
    /// 执行时机：方法执行之前
    /// </summary>
    public class CacheNameResolver
    {
        /// <summary>
        /// 解析正确的TotalName,方法执行前调用---------和下面方法的逻辑一样，只是必须改ActionExecuitingContext的时机而重载下面的一样的方法
        /// </summary>
        /// <param name="TotalName"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        
        public static string ResolveTotalName([Required]string TotalName,ActionExecutingContext context)
        {
            //目标缓存名
            string TargetCacheName = TotalName;

            

            //获取方法的所有参数信息(这个方法可以获取参数的属性&名称信息，无法拿到参数的值
            List<ParameterDescriptor> parameters_list = context.ActionDescriptor.Parameters.ToList();

            //这个方法可以拿到值，但不能获取参数的属性信息
            IDictionary<string, object> argsMap = context.ActionArguments;

            //item==切面方法参数
            parameters_list.ForEach(item => {

                //如果参数为基础类型，则直接替换为参数值
                if (TargetCacheName.Contains("#" + item.Name) && IsBasicType(item.ParameterType))
                {
                    TargetCacheName =  TargetCacheName.Replace("#" + item.Name, argsMap[item.Name].ToString());
                }

                //接下来考虑参数为引用类型的情况下,再去获取一次下属属性

                PropertyInfo[] propertyInfos = item.ParameterType.GetProperties();

                foreach(PropertyInfo pro in propertyInfos)
                {
                    //如果是引用类型则通过.可以获取下属的属性值
                    if (TargetCacheName.Contains("#" + item.Name + "." + pro.Name)&&IsBasicType(pro.PropertyType))
                    {
                        TargetCacheName = TargetCacheName.Replace("#" + item.Name + "." + pro.Name, pro.GetValue(argsMap[item.Name]).ToString());
                    }
                }

                
            });

            return TargetCacheName;
        }


       

       



        //工具方法-------判断一个类型是否是基础数据类型
        public static bool IsBasicType(Type type)
        {
            if (type.Equals(typeof(int)) ||
                type.Equals(typeof(double)) ||
                type.Equals(typeof(float)) ||
                type.Equals(typeof(bool)) ||
                type.Equals(typeof(string)) ||
                type.Equals(typeof(byte)) ||
                type.Equals(typeof(char)) ||
                type.Equals(typeof(long)) ||
                type.Equals(typeof(DateTime)) ||
                type.Equals(typeof(decimal))
                )
            {
                return true;
            }
            return false;
        }

    }
}
